package com.dong.oss.service;

import com.dong.oss.config.MigrationProperties;
import com.dong.oss.dto.MigrationRequest;
import com.dong.oss.dto.MigrationResult;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.io.InputStream;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

/**
 * 迁移服务类
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class MigrationService {
    
    private final MinioService minioService;
    private final OssService ossService;
    private final MigrationProperties migrationProperties;
    
    /**
     * 执行完整迁移
     * 
     * @param request 迁移请求
     * @return 迁移结果
     */
    public MigrationResult migrate(MigrationRequest request) {
        LocalDateTime startTime = LocalDateTime.now();
        long startMs = System.currentTimeMillis();
        
        log.info("开始执行迁移任务，请求参数: {}", request);
        
        MigrationResult.MigrationResultBuilder resultBuilder = MigrationResult.builder()
                .startTime(startTime)
                .successFiles(new ArrayList<>())
                .failureFiles(new ArrayList<>())
                .skippedFiles(new ArrayList<>());
        
        try {
            // 检查源和目标存储桶
            if (!minioService.bucketExists()) {
                throw new RuntimeException("MinIO源存储桶不存在");
            }
            
            if (!ossService.doesBucketExist()) {
                throw new RuntimeException("OSS目标存储桶不存在");
            }
            
            // 获取要迁移的文件列表
            List<String> objectNames = getObjectsToMigrate(request);
            
            if (objectNames.isEmpty()) {
                log.info("没有找到需要迁移的文件");
                return resultBuilder
                        .success(true)
                        .totalFiles(0)
                        .successCount(0)
                        .failureCount(0)
                        .skippedCount(0)
                        .endTime(LocalDateTime.now())
                        .durationMs(System.currentTimeMillis() - startMs)
                        .build();
            }
            
            log.info("找到 {} 个文件需要迁移", objectNames.size());
            
            // 执行批量迁移
            MigrationResult result = migrateBatch(objectNames, request, resultBuilder, startMs);
            
            log.info("迁移任务完成，总文件数: {}，成功: {}，失败: {}，跳过: {}", 
                    result.getTotalFiles(), result.getSuccessCount(), 
                    result.getFailureCount(), result.getSkippedCount());
            
            return result;
            
        } catch (Exception e) {
            log.error("迁移任务执行失败", e);
            return resultBuilder
                    .success(false)
                    .errorMessage(e.getMessage())
                    .endTime(LocalDateTime.now())
                    .durationMs(System.currentTimeMillis() - startMs)
                    .build();
        }
    }
    
    /**
     * 获取需要迁移的对象列表
     */
    private List<String> getObjectsToMigrate(MigrationRequest request) {
        List<String> objectNames;
        
        // 根据前缀获取对象列表
        if (request.getPrefix() != null && !request.getPrefix().trim().isEmpty()) {
            objectNames = minioService.listObjects(request.getPrefix().trim());
        } else {
            objectNames = minioService.listObjects();
        }
        
        // 如果只迁移图片文件，进行过滤
        if (request.isImageOnly()) {
            objectNames = filterImageFiles(objectNames);
        }
        
        return objectNames;
    }
    
    /**
     * 过滤图片文件
     */
    private List<String> filterImageFiles(List<String> objectNames) {
        List<String> supportedFormats = migrationProperties.getSupportedImageFormats();
        if (supportedFormats == null || supportedFormats.isEmpty()) {
            return objectNames;
        }
        
        return objectNames.stream()
                .filter(name -> {
                    String extension = getFileExtension(name).toLowerCase();
                    return supportedFormats.contains(extension);
                })
                .toList();
    }
    
    /**
     * 获取文件扩展名
     */
    private String getFileExtension(String fileName) {
        int lastDotIndex = fileName.lastIndexOf('.');
        return lastDotIndex > 0 ? fileName.substring(lastDotIndex + 1) : "";
    }
    
    /**
     * 批量迁移文件
     */
    private MigrationResult migrateBatch(List<String> objectNames, MigrationRequest request, 
                                       MigrationResult.MigrationResultBuilder resultBuilder, long startMs) {
        
        int batchSize = request.getBatchSize() != null ? request.getBatchSize() : migrationProperties.getBatchSize();
        int totalFiles = objectNames.size();
        int successCount = 0;
        int failureCount = 0;
        int skippedCount = 0;
        
        List<String> successFiles = new ArrayList<>();
        List<String> failureFiles = new ArrayList<>();
        List<String> skippedFiles = new ArrayList<>();
        
        // 使用线程池并发处理
        ExecutorService executor = Executors.newFixedThreadPool(Math.min(batchSize, 10));
        
        try {
            // 分批处理
            for (int i = 0; i < totalFiles; i += batchSize) {
                int endIndex = Math.min(i + batchSize, totalFiles);
                List<String> batch = objectNames.subList(i, endIndex);
                
                log.info("处理批次 {}-{}，共 {} 个文件", i + 1, endIndex, batch.size());
                
                // 并发处理当前批次
                List<CompletableFuture<MigrationFileResult>> futures = batch.stream()
                        .map(objectName -> CompletableFuture.supplyAsync(() -> 
                                migrateFile(objectName, request), executor))
                        .toList();
                
                // 等待所有任务完成
                CompletableFuture<Void> allFutures = CompletableFuture.allOf(
                        futures.toArray(new CompletableFuture[0]));
                
                try {
                    allFutures.get(migrationProperties.getTimeout(), TimeUnit.SECONDS);
                } catch (Exception e) {
                    log.warn("批次处理超时，部分文件可能未完成", e);
                }
                
                // 收集结果
                for (CompletableFuture<MigrationFileResult> future : futures) {
                    try {
                        MigrationFileResult result = future.get();
                        switch (result.getStatus()) {
                            case SUCCESS:
                                successCount++;
                                successFiles.add(result.getObjectName());
                                break;
                            case FAILURE:
                                failureCount++;
                                failureFiles.add(result.getObjectName());
                                break;
                            case SKIPPED:
                                skippedCount++;
                                skippedFiles.add(result.getObjectName());
                                break;
                        }
                    } catch (Exception e) {
                        failureCount++;
                        log.error("获取文件迁移结果失败", e);
                    }
                }
            }
        } finally {
            executor.shutdown();
            try {
                if (!executor.awaitTermination(30, TimeUnit.SECONDS)) {
                    executor.shutdownNow();
                }
            } catch (InterruptedException e) {
                executor.shutdownNow();
                Thread.currentThread().interrupt();
            }
        }
        
        return resultBuilder
                .success(failureCount == 0)
                .totalFiles(totalFiles)
                .successCount(successCount)
                .failureCount(failureCount)
                .skippedCount(skippedCount)
                .successFiles(successFiles)
                .failureFiles(failureFiles)
                .skippedFiles(skippedFiles)
                .endTime(LocalDateTime.now())
                .durationMs(System.currentTimeMillis() - startMs)
                .build();
    }
    
    /**
     * 迁移单个文件
     */
    private MigrationFileResult migrateFile(String objectName, MigrationRequest request) {
        try {
            // 确定目标对象名
            String targetObjectName = determineTargetObjectName(objectName, request);
            
            // 检查目标文件是否已存在
            if (!request.isOverwrite() && ossService.doesObjectExist(targetObjectName)) {
                log.debug("目标文件已存在，跳过: {}", targetObjectName);
                return new MigrationFileResult(objectName, MigrationStatus.SKIPPED);
            }
            
            // 从MinIO下载文件
            try (InputStream inputStream = minioService.downloadObject(objectName)) {
                // 上传到OSS
                boolean uploadSuccess = ossService.uploadObject(objectName, targetObjectName, 
                        inputStream, -1); // -1表示未知长度，让OSS自动计算
                
                if (uploadSuccess) {
                    log.debug("文件迁移成功: {} -> {}", objectName, targetObjectName);
                    return new MigrationFileResult(objectName, MigrationStatus.SUCCESS);
                } else {
                    log.warn("文件上传失败: {} -> {}", objectName, targetObjectName);
                    return new MigrationFileResult(objectName, MigrationStatus.FAILURE);
                }
            }
            
        } catch (Exception e) {
            log.error("文件迁移失败: {}", objectName, e);
            return new MigrationFileResult(objectName, MigrationStatus.FAILURE);
        }
    }
    
    /**
     * 确定目标对象名
     */
    private String determineTargetObjectName(String sourceObjectName, MigrationRequest request) {
        if (request.getTargetPrefix() != null && !request.getTargetPrefix().trim().isEmpty()) {
            String prefix = request.getTargetPrefix().trim();
            if (!prefix.endsWith("/")) {
                prefix += "/";
            }
            return prefix + sourceObjectName;
        }
        return sourceObjectName;
    }
    
    /**
     * 文件迁移结果内部类
     */
    private static class MigrationFileResult {
        private final String objectName;
        private final MigrationStatus status;
        
        public MigrationFileResult(String objectName, MigrationStatus status) {
            this.objectName = objectName;
            this.status = status;
        }
        
        public String getObjectName() {
            return objectName;
        }
        
        public MigrationStatus getStatus() {
            return status;
        }
    }
    
    /**
     * 迁移状态枚举
     */
    private enum MigrationStatus {
        SUCCESS, FAILURE, SKIPPED
    }
}